package com.like;

import ohos.agp.components.element.Element;
import ohos.agp.components.element.PixelMapElement;
import ohos.agp.components.element.VectorElement;
import ohos.agp.utils.Color;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;
import ohos.global.resource.NotExistException;
import ohos.global.resource.Resource;
import ohos.global.resource.ResourceManager;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import ohos.media.image.SourceDataMalformedException;
import ohos.media.image.common.PixelFormat;
import ohos.media.image.common.Rect;
import ohos.media.image.common.Size;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * Created by Joel on 23/12/2015.
 */
public class Utils {
    private static final HiLogLabel LABEL = new HiLogLabel(3, 0xD000B00, "[Utils]");

    /**
     * Check the value range
     *
     * @param value    value
     * @param fromLow  fromLow
     * @param fromHigh fromHigh
     * @param toLow    toLow
     * @param toHigh   toHigh
     * @return value
     */
    public static double mapValueFromRangeToRange(double value, double fromLow,
                                                  double fromHigh, double toLow, double toHigh) {
        return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow));
    }

    /**
     * clamp value
     *
     * @param value value
     * @param low   low
     * @param high  high
     * @return clampValue clampValue
     */
    public static double clamp(double value, double low, double high) {
        return Math.min(Math.max(value, low), high);
    }

    /**
     * Get default icon
     *
     * @return icons
     */
    public static List<Icon> getIcons() {
        List<Icon> icons = new ArrayList<>();
        icons.add(new Icon(ResourceTable.Graphic_heart_on, ResourceTable.Graphic_heart_off, IconType.Heart));
        icons.add(new Icon(ResourceTable.Graphic_star_on, ResourceTable.Graphic_star_off, IconType.Star));
        icons.add(new Icon(ResourceTable.Graphic_thumb_on, ResourceTable.Graphic_thumb_off, IconType.Thumb));
        return icons;
    }


    private static PixelMap.InitializationOptions getOptions(int width, int height) {
        PixelMap.InitializationOptions opts = new PixelMap.InitializationOptions();
        opts.size = new Size(width, height);
        opts.pixelFormat = PixelFormat.ARGB_8888;
        return opts;
    }

    /**
     * Resize the image
     *
     * @param element element
     * @param width   width
     * @param height  height
     * @return Element
     */
    public static Element resizeDrawable(Element element, int width, int height) {
        PixelMap bitmap = getBitmap(element, width, height);
        return new PixelMapElement(PixelMap.create(bitmap, getOptions(width, height)));
    }

    private static PixelMap getBitmap(Element element, int width, int height) {
        if (element instanceof PixelMapElement) {
            return ((PixelMapElement) element).getPixelMap();
        }
        return null;
    }

    /**
     * Convert dp to pixel
     *
     * @param context  context
     * @param dipValue dipValue
     * @return pixelValue
     */
    public static float dipToPixels(Context context, int dipValue) {
        final float scale = DisplayManager.getInstance().getDefaultDisplay(context).get().getAttributes().densityPixels;
        return (int) (dipValue * scale + 0.5f);
    }

    /**
     * * Prepare pixelmapelement from resource
     *
     * @param resource resource
     * @return PixelMapElement
     * @throws IOException       IOException
     * @throws NotExistException NotExistException
     */
    public static Optional<PixelMapElement> prepareElement(Resource resource) throws IOException, NotExistException {
        Optional<PixelMap> pixelMap = preparePixelmap(resource);
        if (pixelMap.isPresent()) {
            PixelMapElement pixelMapElement = new PixelMapElement(pixelMap.get());
            return Optional.of(pixelMapElement);
        }
        return Optional.empty();
    }

    /**
     * getElementByResId
     *
     * @param resourceId Resource Id
     * @param context    Context Value
     * @return Optional<PixelMapElement></PixelMapElement>
     */
    public static Element getElementByResId(Context context, int resourceId) {
        ResourceManager resourceManager = context.getResourceManager();
        if (resourceManager == null) {
            return null;
        }
        Optional<PixelMapElement> element = Optional.empty();
        if (resourceId != 0) {
            try {
                Resource resource = resourceManager.getResource(resourceId);
                element = prepareElement(resource);
            } catch (IOException | NotExistException e) {
            }
        }
        if (element.isPresent()) {
            return element.get();
        } else {
            return new VectorElement(context, resourceId);
        }
    }

    /**
     * * Create pixelmap from resource
     *
     * @param resource resource
     * @return PixelMap
     * @throws IOException IOException
     */
    public static Optional<PixelMap> preparePixelmap(Resource resource) throws IOException {
        PixelMap decodePixelMap = null;
        try {
            if (resource != null) {
                byte[] bytes = readBytes(resource);
                resource.close();
                if (bytes == null) {
                    HiLog.error(LABEL, "get pixelmap failed, read resource bytes is null");
                    return Optional.empty();
                }
                ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions();
                ImageSource imageSource = ImageSource.create(bytes, srcOpts);
                if (imageSource == null) {
                    HiLog.error(LABEL, "get pixelmap failed, image source is null");
                }
                ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions();
                decodingOpts.desiredSize = new Size(0, 0);
                decodingOpts.desiredRegion = new Rect(0, 0, 0, 0);
                decodingOpts.desiredPixelFormat = PixelFormat.ARGB_8888;
                if (imageSource != null) {
                    decodePixelMap = imageSource.createPixelmap(decodingOpts);
                }
            }
        } catch (IOException | SourceDataMalformedException e) {
            HiLog.error(LABEL, "get pixelmap failed, read resource bytes failed");
            return Optional.empty();
        }
        return Optional.ofNullable(decodePixelMap);
    }


    private static byte[] readBytes(Resource resource) {
        if (resource != null) {
            final int bufferSize = 1024;
            final int ioEnd = -1;

            ByteArrayOutputStream output = new ByteArrayOutputStream();
            byte[] bytes = new byte[bufferSize];
            byte[] bytesArray = new byte[0];
            while (true) {
                try {
                    int readLen = resource.read(bytes, 0, bufferSize);
                    if (readLen == ioEnd) {
                        bytesArray = output.toByteArray();
                        break;
                    }
                    output.write(bytes, 0, readLen);
                } catch (IOException e) {
                    break;
                } finally {
                    try {
                        output.close();
                    } catch (IOException e) {
                        HiLog.error(LABEL, "close output failed");
                    }
                }
            }
            return bytesArray;
        } else {
            return new byte[]{};
        }
    }


    /**
     * Convert string dimension to int
     *
     * @param value string dimension
     * @return dimension
     */
    public static int getIntFromDimensionString(String value) {
        return Integer.parseInt(value.substring(0, value.length() - 2));
    }

    /**
     * Create PixelMap with size
     *
     * @param width       width
     * @param height      height
     * @param pixelFormat pixelFormat
     * @return PixelMap
     */
    public static PixelMap createPixelMap(int width, int height, PixelFormat pixelFormat) {
        PixelMap.InitializationOptions initializationOptions = new PixelMap.InitializationOptions();
        initializationOptions.pixelFormat = pixelFormat;
        initializationOptions.size = new Size(width == 0 ? 100 : width, height == 0 ? 100 : height);
        return PixelMap.create(initializationOptions);
    }


    /**
     * Parse the color code from string
     *
     * @param value color String value
     * @return int color valve
     */
    public static int getColorFromString(String value) {
        int color;
        if (value.length() == 4) {
            String str = "#"
                    + "0" + value.charAt(1)
                    + "0" + value.charAt(2)
                    + "0" + value.charAt(3);
            color = Color.getIntColor(str);
        } else {
            try {
                color = Color.getIntColor(value);
            } catch (IllegalArgumentException e) {
                return Color.TRANSPARENT.getValue();
            }
        }
        return color != 0 ? color : Color.TRANSPARENT.getValue();
    }

    /**
     * Convert Alpha int value to float
     *
     * @param value int alpha
     * @return float alpha
     */
    public static float getAlphaFromInt(int value) {
        return (((float) value) / 255.0f);
    }
}

